#pragma once

#include "ScenePrecompiled.hxx"
#include "SceneTransformationBase.hxx"
#include "SceneChildContext.hxx"
#include "SceneUniqueChild.hxx"

namespace Eifersucht
{
	// Prototypes 

	class Scene; TinyTypeDecl( Scene ); // Nodes are primarily used to specify the position, rotation and scale of scene elements within a scene.
	class SceneChild; TinyTypeDecl( SceneChild ); // Nodes are primarily used to specify the position, rotation and scale of scene elements within a scene.
	typedef std::vector<SceneChildPtr> SceneChildren;
	// Implementation

	// Represents the scene node (basically its tranformation) and the node collection
	class SceneChild : public TransformationBase, public UniqueChild<SceneChild>
	{
		// Defines the SceneChild internal implementation and all the Fbx library interop.
		struct _Internal_impl; typedef _Internal_impl Impl; TinyTypeDecl( Impl );
		typedef SceneChildContext::Type ContextType; TinyTypeDecl( ContextType );
		friend SceneChild::_Internal_impl;
		friend Scene;

	public:

		virtual ~SceneChild();

		inline UInt32 GetChildrenCount() { return m_Children.size(); }
		inline SceneChildContextPtr GetChildContext() { return m_pContext; }
		template <class TContext> inline TContext* GetTypedChildContext() { return dynamic_cast<TContext*>(m_pContext); }
		inline SceneChildAddress GetChildAt( _In_ UInt32 iChild, _Out_opt_ SceneChildAddress ppChild = nullptr ) 
		{ 
			if ( GetChildrenCount() <= iChild ) { if ( ppChild ) ppChild = nullptr; return nullptr; }
			else if ( ppChild ) { ppChild = &m_Children[iChild]; return &m_Children[iChild]; }
			else { return &m_Children[iChild]; }
		} 

		ContextType GetChildContextType( _No_args_ );

		// Indicates whether the scene child is the scene root 
		Bool IsRootChild( _No_args_ ) const;

		void SetParentChild( _In_opt_ SceneChildPtr pChild );
		SceneChildPtr GetParentChild();

		void SetParentScene( _In_opt_ ScenePtr pScene );
		ScenePtr GetParentScene();

		void SetName( _In_z_ String8 szName );
		Eifersucht::String8 GetName( _No_args_ ) const;

		SceneChildPtr FindByName( _In_z_ String8 szName, _In_opt_ bool bRecursively = true );
		SceneChildPtr FindById( _In_z_ uint32 uId, _In_opt_ bool bRecursively = true );

	protected: // Force abstract

		SceneChild( _In_opt_ SceneChildPtr pChild );

	protected:

		void InternalRestart( _No_args_ );
		void InternalRelease( _No_args_ );
		void ReleaseExternalResourcesRecursively( _No_args_ );

		Eifersucht::SceneChildContextPtr m_pContext; // Node content
		Eifersucht::SceneChildPtr m_pParentChild; // The link to the parent scene node 
		Eifersucht::SceneChildren m_Children;
		Eifersucht::ScenePtr m_pParentScene; // The link to the parent scene 
		Eifersucht::String8 m_Name;
		bool m_bIsRootChild; // Indicates whether the scene child is the scene root 

		ImplPtr m_pImpl;
	};
	
};